package com.maikang.exammall.exception;

import com.maikang.exammall.entity.constant.BizCode;
import com.maikang.exammall.entity.dto.ResponseDTO;
import lombok.extern.log4j.Log4j2;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.StringJoiner;

import static com.maikang.exammall.entity.constant.BizCode.BadRequest;
import static com.maikang.exammall.entity.constant.BizCode.InternalServerException;
import static com.maikang.exammall.entity.constant.BizCode.NotExist;
import static com.maikang.exammall.entity.constant.BizCode.MethodForbidden;
import static com.maikang.exammall.entity.constant.BizCode.DuplicateKey;

@Log4j2
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * customized exception
     */
    @ExceptionHandler(JpaConverterException.class)
    public ResponseDTO handleJpaConverterException(JpaConverterException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO<>(InternalServerException, e.getMessage());
    }

    @ExceptionHandler(UnauthorizedException.class)
    public ResponseDTO handleUnauthorizedException(UnauthorizedException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO<>(BizCode.Unauthorized, "token 已经过期失效， 请重新打开迈康微信公众号同意授权进入");
    }

    @ExceptionHandler(MobileNotBoundException.class)
    public ResponseDTO handleMobileNotBoundException(MobileNotBoundException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO<>(BizCode.MobileNotBound, "用户尚未绑定手机");
    }


    @ExceptionHandler(ForbiddenException.class)
    public ResponseDTO handleForbiddenException(ForbiddenException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO<>(BizCode.Forbidden, "用户无权限访问该接口");
    }

    @ExceptionHandler(BadRequestException.class)
    public ResponseDTO handleBadRequestException(BadRequestException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO<>(BadRequest, e.getMessage());
    }

    @ExceptionHandler(BindException.class)
    public ResponseDTO handleBindException(BindException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO(BadRequest, e.getMessage());
    }


    /**
     * method parameter validation
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseDTO handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        FieldError fieldError = e.getBindingResult().getFieldError();
        return new ResponseDTO(BadRequest, fieldError.getField() + " " + fieldError.getDefaultMessage());
    }


    /**
     * ValidationException
     */
    @ExceptionHandler(ValidationException.class)
    public ResponseDTO handleValidationException(ValidationException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO(BadRequest, e.getCause().getMessage());
    }

    /**
     * ConstraintViolationException
     * ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseDTO handleConstraintViolationException(ConstraintViolationException e) {
        log.error(e.getMessage(), e);
        StringJoiner sj = new StringJoiner(";");
        e.getConstraintViolations().forEach(x -> sj.add(x.getMessageTemplate()));
        return new ResponseDTO(BadRequest, sj.toString());
    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseDTO handlerNoFoundException(Exception e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO(NotExist, "路径不存在，请检查路径是否正确");
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseDTO handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO(MethodForbidden, "不支持'" + e.getMethod() + "'请求方法");
    }


    @ExceptionHandler(DuplicateKeyException.class)
    public ResponseDTO handleDuplicateKeyException(DuplicateKeyException e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO(DuplicateKey, "数据重复,请检查后提交");
    }


    @ExceptionHandler(Exception.class)
    public ResponseDTO handleException(Exception e) {
        log.error(e.getMessage(), e);
        return new ResponseDTO(-500, "系统繁忙,请稍后再试");
    }
}
